using System.Security.Cryptography;

namespace Digitalmes.Common.Utils;

/// <summary>
/// 加密解密帮助类。
/// </summary>
public static class CryptoUtils
{
    private static readonly byte[] s_keys = [0x41, 0x72, 0x65, 0x79, 0x6F, 0x75, 0x6D, 0x79, 0x53, 0x6E, 0x6F, 0x77, 0x6D, 0x61, 0x6E, 0x3F];

    /// <summary>
    /// 对称加密算法AES(块式加密算法)
    /// </summary>
    /// <param name="encryptString">待加密字符串</param>
    /// <param name="encryptKey">加密密钥，须半角字符</param>
    /// <param name="mode">加密模式</param>
    /// <returns>加密结果字符串</returns>
    public static string AESEncrypt(string encryptString, string encryptKey, CipherMode mode = CipherMode.CBC)
    {
        string encryptKey2;
        if (encryptKey.Length < 32)
        {
            encryptKey2 = encryptKey.PadRight(32, ' ');
        }
        else
        {
            encryptKey2 = encryptKey.Length == 32 ? encryptKey : encryptKey[..32];
        }

        var key = Encoding.UTF8.GetBytes(encryptKey2);
        return AESEncrypt(encryptString, key, mode);
    }

    /// <summary>
    /// 对称加密算法AES加密(块式加密算法)
    /// </summary>
    /// <param name="encryptString">待加密字符串</param>
    /// <param name="encryptKey">加密密钥，须半角字符</param>
    /// <param name="mode">加密模式</param>
    /// <returns>加密结果字符串，转换为 Base64</returns>
    public static string AESEncrypt(string encryptString, byte[] encryptKey, CipherMode mode = CipherMode.CBC)
    {
        using var aes = Aes.Create();
        aes.Key = encryptKey;
        aes.IV = s_keys;
        aes.Mode = mode;
        using var rijndaelEncrypt = aes.CreateEncryptor();
        var inputData = Encoding.UTF8.GetBytes(encryptString);
        var encryptedData = rijndaelEncrypt.TransformFinalBlock(inputData, 0, inputData.Length);
        return Convert.ToBase64String(encryptedData);
    }

    /// <summary>
    /// 对称加密算法AES解密字符串
    /// </summary>
    /// <param name="decryptString">待解密的字符串</param>
    /// <param name="decryptKey">解密密钥,和加密密钥相同</param>
    /// <param name="mode">加密模式</param>
    /// <returns>解密成功返回解密后的字符串,失败返回空</returns>
    public static string AESDecrypt(string decryptString, string decryptKey, CipherMode mode = CipherMode.CBC)
    {
        string decryptKey2;
        if (decryptKey.Length < 32)
        {
            decryptKey2 = decryptKey.PadRight(32, ' ');
        }
        else
        {
            decryptKey2 = decryptKey.Length == 32 ? decryptKey : decryptKey[..32];
        }

        var key = Encoding.UTF8.GetBytes(decryptKey2);
        return AESDecrypt(decryptString, key, mode);
    }

    /// <summary>
    /// 对称加密算法AES解密字符串
    /// </summary>
    /// <param name="decryptString">待解密的字符串（Base64）</param>
    /// <param name="decryptKey">解密密钥,和加密密钥相同</param>
    /// <param name="mode">加密模式</param>
    /// <returns>解密成功返回解密后的字符串,失败返回空</returns>
    public static string AESDecrypt(string decryptString, byte[] decryptKey, CipherMode mode = CipherMode.CBC)
    {
        try
        {
            using var aes = Aes.Create();
            aes.Key = decryptKey;
            aes.IV = s_keys;
            aes.Mode = mode;
            using var rijndaelDecrypt = aes.CreateDecryptor();
            var inputData = Convert.FromBase64String(decryptString);
            var decryptedData = rijndaelDecrypt.TransformFinalBlock(inputData, 0, inputData.Length);
            return Encoding.UTF8.GetString(decryptedData);
        }
        catch
        {
            return string.Empty;
        }
    }

    /// <summary>
    /// 对字符串进行MD5摘要
    /// </summary>
    /// <param name="message">需要摘要的字符串</param>
    /// <returns>MD5摘要字符串</returns>
    public static string MDString(string message)
    {
        var buffer = Encoding.Default.GetBytes(message);
        var bytes = MD5.HashData(buffer);
        return ByteArray2HexString(bytes);
    }

    /// <summary>
    /// Base64加密
    /// </summary>
    /// <param name="str">需要加密的字符串</param>
    /// <returns>加密后的数据</returns>
    public static string Base64Encrypt(string str)
    {
        var encbuff = Encoding.UTF8.GetBytes(str);
        return Convert.ToBase64String(encbuff);
    }

    /// <summary>
    /// Base64解密
    /// </summary>
    /// <param name="str">需要解密的字符串</param>
    /// <returns>解密后的数据</returns>
    public static string Base64Decrypt(this string str)
    {
        try
        {
            var decbuff = Convert.FromBase64String(str);
            return Encoding.UTF8.GetString(decbuff);
        }
        catch
        {
            return str;
        }
    }

    /// <summary>
    /// byte数组转换为十六进制字符串。
    /// </summary>
    /// <param name="bytes"></param>
    /// <returns></returns>
    private static string ByteArray2HexString(byte[] bytes)
    {
        var array = new char[bytes.Length << 1];
        for (var j = 0; j < array.Length; j += 2)
        {
            var b = bytes[j >> 1];
            array[j] = GetHexValue(b >> 4);
            array[j + 1] = GetHexValue(b & 0xF);
        }

        return new string(array, 0, array.Length);

        static char GetHexValue(int i)
        {
            return i < 10 ? (char)(i + 48) : (char)(i - 10 + 97);
        }
    }
}
